package setting

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"

	"code.google.com/awwwe-browser/auralvm/conversation"
	"code.google.com/awwwe-browser/auralvm/param"
	"code.google.com/awwwe-browser/data"
	"code.google.com/awwwe-browser/slurp"
)

// Alternative HTTP handler for sending data back to the view.
var NextContinuer func(http.ResponseWriter, *http.Request, string)
// Final alternative HTTP handler for sending data back to the view.
var StopContinuer func(http.ResponseWriter, *http.Request, string)

func init() {
	BrowserSettings = GetSettings()
}

type SettingHelpLevel int

const (
	_                                  = iota
	SettingHelpLevel1 SettingHelpLevel = iota
	SettingHelpLevel2
	SettingHelpLevel3
)

var (
	SettingHelpLevel1String string = "a lot of"
	SettingHelpLevel2String string = "a little"
	SettingHelpLevel3String string = "no"
)

var BrowserSettings Settings

type Settings struct {
	HelpLevel SettingHelpLevel
}

// Settings constructor.
func buildSettings() Settings {
	var v Settings
	v.HelpLevel = SettingHelpLevel1
	return v
}

// HelpString returns a SettingHelpLevel?String used to describe the help setting to the user.
func (this *Settings) HelpString() string {
	if this.HelpLevel == SettingHelpLevel1 {
		return SettingHelpLevel1String
	} else if this.HelpLevel == SettingHelpLevel2 {
		return SettingHelpLevel2String
	}
	// this.HelpLevel == SettingHelpLevel3
	return SettingHelpLevel3String
}

// Save writes the settings to the file.
func (this *Settings) Save() error {
	var markup []byte
	var err error
	var file *os.File
	markup, err = json.MarshalIndent(this, "", "  ")
	if err == nil {
		file, err = os.Create(param.LocalSettingFilePath)
		defer file.Close()
		if err == nil {
			_, err = file.Write(markup)
		}
	}
	return err
}

// GetSettings reads the settings from the file.
func GetSettings() Settings {
	var v Settings
	var markup []byte
	var err error
	v = buildSettings()
	markup, err = slurp.SlurpFile(param.LocalSettingFilePath)
	if err == nil {
		err = json.Unmarshal(markup, &v)
	}
	return v
}

// HandlerSettingsListTools handles an http request to list the settings tools for the view.
func HandlerSettingsListTools(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	ContinuerSettingsListTools(w, r, data.EmptyString, 0, true)
}

// ContinuerSettingsListTools continues with handling an http request to list the settings tools.
func ContinuerSettingsListTools(w http.ResponseWriter, r *http.Request, intro string, startoptionsat int, continueon bool) {
	var err error
	var conv conversation.Conversation
	var option conversation.APIOption
	var jsonbb []byte
	conv = conversation.BuildConversation()
	conv.Type = conversation.ConversationTypeOptions
	conv.Intro = intro
	conv.InitialIndex = startoptionsat
	conv.Header.Append("This tool lets you edit your browser settings.")
	conv.Header.Append("I will iterate through the settings and tell you the name of the setting and how it is set.")
	conv.Helpful = "After i say the name of a setting, say yes, if you want to edit that setting."
	conv.MoreHelpful = "You may say yes, no, back, restart, finish, pause, help or quit."
	conv.Footer = "That is the end of the list of the browser settings."
	conv.CallHelp.Package = param.Package
	conv.CallHelp.Object = "browser"
	conv.CallHelp.Method = "listtools"
	conv.InitialIndex = startoptionsat
	// the help setting
	option = conversation.BuildAPIOption()
	option.VXMLs.Append("The help setting.")
	option.VXMLs.Append(fmt.Sprintf("You have the help set to, %s help.", BrowserSettings.HelpString()))
	/*
	    if BrowserSettings.HelpLevel != SettingHelpLevel3 {
			option.VXMLs.Append("Would you like to edit this setting?")
	    }
	*/
	option.CallYes.Package = param.Package
	option.CallYes.Object = "settings"
	option.CallYes.Method = "edithelp"
	option.CallYes.Arguments[param.ParamSourceObject] = "settings"
	option.CallYes.Arguments[param.ParamSourceMethod] = "listtools"
	option.CallYes.Arguments[param.ParamSourceOptionIndex] = "1"
	conv.Options = append(conv.Options, option)
	// serialize the conversation
	jsonbb, err = conv.Marshal()
	if err == nil {
		w.Write(jsonbb)
	} else {
		if continueon {
			NextContinuer(w, r, intro)
		} else {
			// internal server error
			StopContinuer(w, r, intro)
		}
	}
}

// HandlerSettingsListTools handles an http request to edit the settings for the view.
func HandlerSettingsHelpEdit(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	ContinuerSettingsHelpEdit(w, r, data.EmptyString, true)
}

// ContinuerSettingsHelpEdit continues with handling an http request to ledit the settings.
func ContinuerSettingsHelpEdit(w http.ResponseWriter, r *http.Request, intro string, continueon bool) {
	var err error
	var conv conversation.Conversation
	var jsonbb []byte
	var fco *param.FormControlOption
	conv = conversation.BuildConversation()
	conv.Type = conversation.ConversationTypeFormSingleSelect
	conv.Intro = intro
	conv.Header.Append("This setting sets how much help you get from the browser.")
	conv.Helpful = "I will speak each option to you. After i speak an option to you, say yes, if you want to select that option."
	conv.MoreHelpful = "you may say yes, back, restart, finish, help, pause, or quit."
	conv.Footer = "That is the end of the list of the browser help setting options."
	conv.CallHelp.Package = param.Package
	conv.CallHelp.Object = "settings"
	conv.CallHelp.Method = "listtools"
	conv.CallYes.Package = param.Package
	conv.CallYes.Object = "settings"
	conv.CallYes.Method = "sethelp"
	// after the user saves the help setting continue on with the list of settings tools
	conv.CallYes.Arguments[param.ParamSourceObject] = "settings"
	conv.CallYes.Arguments[param.ParamSourceMethod] = "listtools"
	conv.CallYes.Arguments[param.ParamSourceOptionIndex] = "-1"
	// a lot of help
	fco = param.NewFormControlOption()
	fco.VXMLs.Append(fmt.Sprintf("%s help.", SettingHelpLevel1String))
	fco.Value = fmt.Sprintf("%d", int(SettingHelpLevel1))
	fco.DefaultSelected = BrowserSettings.HelpLevel == SettingHelpLevel1
	conv.MenuOptions = append(conv.MenuOptions, fco)
	// a little help
	fco = param.NewFormControlOption()
	fco.VXMLs.Append(fmt.Sprintf("%s help.", SettingHelpLevel2String))
	fco.Value = fmt.Sprintf("%d", int(SettingHelpLevel2))
	fco.DefaultSelected = BrowserSettings.HelpLevel == SettingHelpLevel2
	conv.MenuOptions = append(conv.MenuOptions, fco)
	// no help
	fco = param.NewFormControlOption()
	fco.VXMLs.Append(fmt.Sprintf("%s help.", SettingHelpLevel3String))
	fco.Value = fmt.Sprintf("%d", int(SettingHelpLevel3))
	fco.DefaultSelected = BrowserSettings.HelpLevel == SettingHelpLevel3
	conv.MenuOptions = append(conv.MenuOptions, fco)
	// serialize the conversation
	jsonbb, err = conv.Marshal()
	if err == nil {
		w.Write(jsonbb)
	} else {
		if continueon {
			NextContinuer(w, r, intro)
		} else {
			// internal server error
			StopContinuer(w, r, intro)
		}
	}
}

// HandlerSettingsListTools handles an http request to save the settings for the view.
func HandlerSettingsHelpSave(w http.ResponseWriter, r *http.Request) {
	var values []string
	var ok bool
	var err error
	var intro string
	var setting int
	r.ParseForm()
	values, ok = r.Form[param.ParamValue]
	if !ok || (ok && len(values) != 1) {
		intro = "I was not able to get your setting because the voice app did not provide the setting."
		NextContinuer(w, r, intro)
		return
	}
	setting, ok = data.StringToInt(values[0])
	if !ok {
		intro = "I was not able to save your help setting because the voice app did not provide a valid setting."
		NextContinuer(w, r, intro)
		return
	}
	if setting != int(SettingHelpLevel1) && setting != int(SettingHelpLevel2) && setting != int(SettingHelpLevel3) {
		intro = "I was not able to save your help setting because the voice app did not provide a valid setting."
		NextContinuer(w, r, intro)
		return
	}
	BrowserSettings.HelpLevel = SettingHelpLevel(setting)
	err = BrowserSettings.Save()
	if err != nil {
		intro = "I was not able to save your setting because i was not able to write the settings file."
	} else {
		intro = fmt.Sprintf("your help setting has been saved and now the browser is giving you %s help.", BrowserSettings.HelpString())
	}
	NextContinuer(w, r, intro)
}
